package com.baor.security;

import com.baor.filter.JwtAuthenticationFilter;
import com.baor.security.handler.CustomHttpBasicServerAuthenticationEntryPoint;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authentication.UserDetailsRepositoryReactiveAuthenticationManager;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.context.NoOpServerSecurityContextRepository;
import reactor.core.publisher.Mono;


@Slf4j
@Configuration
@EnableWebFluxSecurity
public class SecurityConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private JwtAuthenticationFilter jwtAuthenticationFilter;
    // 相当于  AuthenticationManager
    @Bean
    public ReactiveAuthenticationManager reactiveAuthenticationManager(UserDetailServiceImpl userDetailsService,PasswordEncoder passwordEncoder) {
        UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(userDetailsService);
//        System.out.println(passwordEncoder);
        authenticationManager.setPasswordEncoder(passwordEncoder);
        return authenticationManager;
    }


    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http,
                                                            ReactiveAuthenticationManager reactiveAuthenticationManager,
                                                            CustomHttpBasicServerAuthenticationEntryPoint customHttpBasicServerAuthenticationEntryPoint) {
        SecurityWebFilterChain build = http.csrf(ServerHttpSecurity.CsrfSpec::disable)
                .httpBasic(ServerHttpSecurity.HttpBasicSpec::disable)
                .authenticationManager(reactiveAuthenticationManager)
                .exceptionHandling(x -> {
                    x.authenticationEntryPoint(customHttpBasicServerAuthenticationEntryPoint);
                    x.accessDeniedHandler((swe, e) -> {
                        swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                        return swe.getResponse().writeWith(Mono.just(new DefaultDataBufferFactory().wrap("FORBIDDEN".getBytes())));
                    });
                })
                .securityContextRepository(NoOpServerSecurityContextRepository.getInstance())
                .authorizeExchange(x -> {
                    x.pathMatchers("/**").permitAll();
                    x.pathMatchers(HttpMethod.OPTIONS).permitAll();
                    x.anyExchange().authenticated();
                })
                .addFilterAt(jwtAuthenticationFilter, SecurityWebFiltersOrder.HTTP_BASIC)
                .build();
        return build;
    }
}
